﻿using Hinacom.Scheduler;
using Hinacom.Scheduler.Configuration;
using Hinacom.Scheduler.Manager.Utilities;
using Hinacom.Scheduler.Service.Proxy;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace Hinacom.Scheduler.Manager
{
    public partial class MainForm : Form
    {
        public MainForm()
        {
            InitializeComponent();
        }

        private void MainForm_Load(object sender, EventArgs e)
        {
            LoadTasks();
        }

        private void lblLoadingFailed_Click(object sender, EventArgs e)
        {
            LoadTasks();
        }
        private void lstGroups_SelectedIndexChanged(object sender, EventArgs e)
        {
            ListJobsInGroup();
        }
        private void lstGroups_DrawItem(object sender, DrawItemEventArgs e)
        {
            if (e.Index < 0) return;

            Graphics g = e.Graphics;//获取Graphics对象。
            Rectangle bound = e.Bounds;//获取当前要绘制的行的一个矩形范围。
            string text = lstGroups.Items[e.Index].ToString();//获取当前要绘制的行的显示文本。
            if ((e.State & DrawItemState.Selected) == DrawItemState.Selected)
            {
                // 背景
                Brush brush = new SolidBrush(ColorTranslator.FromHtml("#90A4B6"));
                g.FillRectangle(brush, bound.Left + 4, bound.Top + 4, bound.Width - 8, bound.Height - 8);
                //绘制显示文本。
                TextRenderer.DrawText(g, text, new Font(this.Font, FontStyle.Bold),
                    new Rectangle(bound.X + 20, bound.Y, bound.Width - 40, bound.Height),
                    Color.White, TextFormatFlags.VerticalCenter | TextFormatFlags.Left);
            }
            else
            {
                // 背景
                g.FillRectangle(new SolidBrush(lstGroups.BackColor), bound);
                // 文本
                TextRenderer.DrawText(g, text, this.Font,
                    new Rectangle(bound.X + 20, bound.Y, bound.Width - 40, bound.Height),
                    lstGroups.ForeColor, TextFormatFlags.VerticalCenter | TextFormatFlags.Left);
            }
        }
        private void lstJobs_DrawItem(object sender, DrawItemEventArgs e)
        {
            if (e.Index < 0) return;

            Graphics g = e.Graphics;
            Rectangle bound = e.Bounds;

            JobInfo job = lstJobs.Items[e.Index] as JobInfo;
            Color titleColor = lstGroups.ForeColor, subtextColor = Color.Gray;

            if ((e.State & DrawItemState.Selected) == DrawItemState.Selected)
            {
                // 背景
                Brush brush = new SolidBrush(ColorTranslator.FromHtml("#90A4B6"));
                g.FillRectangle(brush, bound.Left + 4, bound.Top + 4, bound.Width - 8, bound.Height - 8);
                titleColor = Color.White;
                subtextColor = Color.White;
            }
            else
            {
                // 背景
                g.FillRectangle(new SolidBrush(lstGroups.BackColor), bound);
            }

            int titleHeight = 30, subtextHeight = 20;
            int currenty = bound.Y + 4;
            TextFormatFlags renderFormats = TextFormatFlags.VerticalCenter | TextFormatFlags.Left | TextFormatFlags.EndEllipsis;

            //绘制显示文本。
            TextRenderer.DrawText(g, job.Name, new Font(this.Font.FontFamily, 10, FontStyle.Bold),
                new Rectangle(bound.X + 20, currenty, bound.Width - 40, titleHeight),
                titleColor, renderFormats);
            currenty += titleHeight;
            /*
            string jobTypeName = job.JobTypeName;
            if (!String.IsNullOrWhiteSpace(jobTypeName))
            {
                var jobtypeConfig = SchedulerConfiguration.Current.JobTypes.Get(jobTypeName);
                if (jobtypeConfig != null)
                    jobTypeName += " (" + jobtypeConfig.Type + ")";

                TextRenderer.DrawText(g, jobTypeName, this.Font,
                    new Rectangle(bound.X + 20, currenty, bound.Width - 40, subtextHeight),
                    subtextColor, renderFormats);
                currenty += subtextHeight;
            }
            */
            if (!String.IsNullOrWhiteSpace(job.Description))
            {
                TextRenderer.DrawText(g, job.Description, this.Font,
                    new Rectangle(bound.X + 20, currenty, bound.Width - 40, subtextHeight),
                    subtextColor, renderFormats);
                currenty += subtextHeight;
            }

            string scheduleDescription = GetScheduleDescription(job);
            if (!String.IsNullOrWhiteSpace(scheduleDescription))
            {
                TextRenderer.DrawText(g, scheduleDescription, this.Font,
                    new Rectangle(bound.X + 20, currenty, bound.Width - 40, subtextHeight),
                    subtextColor, renderFormats);
                currenty += subtextHeight;
            }
        }
        private void newTaskToolStripButton_Click(object sender, EventArgs e)
        {
            NewTask();
        }
        private void newTaskToolStripMenuItem_Click(object sender, EventArgs e)
        {
            NewTask();
        }
        private void refreshToolStripButton_Click(object sender, EventArgs e)
        {
            LoadTasks();
        }
        private void refreshToolStripMenuItem_Click(object sender, EventArgs e)
        {
            LoadTasks();
        }
        private void deleteToolStripButton_Click(object sender, EventArgs e)
        {
            DeleteJob();
        }
        private void deleteTaskToolStripMenuItem_Click(object sender, EventArgs e)
        {
            DeleteJob();
        }
        private void lstJobs_Resize(object sender, EventArgs e)
        {
            lstJobs.Invalidate();
        }
        private void lstJobs_SelectedValueChanged(object sender, EventArgs e)
        {
            RefreshDeleteStatus();

            JobInfo job = (JobInfo)lstJobs.SelectedItem;
            LoadJobRunningHistory(job);
        }
        private void lstHistories_DrawItem(object sender, DrawItemEventArgs e)
        {
            if (e.Index < 0) return;

            Graphics g = e.Graphics;//获取Graphics对象。
            Rectangle bound = e.Bounds;//获取当前要绘制的行的一个矩形范围。
            Font font = this.Font;
            int y = bound.Y, titleHeight = 30, lineHeight = 22;
            Color forePrimaryColor = lstHistories.ForeColor, foreSecondaryColor = Color.Gray, backColor = lstHistories.BackColor;

            JobHistory his = (JobHistory)lstHistories.Items[e.Index];

            string title = his.StartTimeUtc.ToLocalTime().ToString("MM/dd/yyyy HH:mm:ss");

            if ((e.State & DrawItemState.Selected) == DrawItemState.Selected)
            {
                backColor = ColorTranslator.FromHtml("#90A4B6");
                forePrimaryColor = foreSecondaryColor = Color.White;
            }

            // 背景
            Brush brush = new SolidBrush(backColor);
            g.FillRectangle(brush, bound.Left + 4, bound.Top + 4, bound.Width - 8, bound.Height - 8);

            // 标题
            TextRenderer.DrawText(g, title, new Font(font.FontFamily, font.Size + 1.5f, FontStyle.Bold),
                new Rectangle(bound.X + 20, y, bound.Width - 40, titleHeight),
                forePrimaryColor, TextFormatFlags.Bottom | TextFormatFlags.Left);

            y += titleHeight;

            string line = his.Status.ToString() + ".";
            if (his.EndTimeUtc.HasValue)
            {
                line += String.Format(" Completed at {0}", his.EndTimeUtc.Value.ToLocalTime().ToString("HH:mm:ss' on 'MM/dd/yyyy"));
            }
            TextRenderer.DrawText(g, line, font,
                new Rectangle(bound.X + 20, y, bound.Width - 40, lineHeight),
                foreSecondaryColor, TextFormatFlags.VerticalCenter | TextFormatFlags.Left);
        }

        IEnumerable<JobInfo> jobs = null;

        private void LoadTasks()
        {
            jobs = null;

            try
            {
                var proxy = new SchedulerProxy();
                jobs = proxy.GetActiveJobs();
                var groups = jobs.Select(j => j.Group).Distinct().ToList();
                lstGroups.Items.Clear();
                foreach (string group in groups)
                    lstGroups.Items.Add(group);

                lblLoadingFailed.Visible = false;
                lstGroups.Visible = splitter1.Visible = lstJobs.Visible = splitter2.Visible = pnlRightInfo.Visible = true;
            }
            catch (Exception ex)
            {
                Program.Logger.Error("Failed to retrieve active tasks.", ex);
                lstGroups.Visible = splitter1.Visible = lstJobs.Visible = splitter2.Visible = pnlRightInfo.Visible = false;
                lblLoadingFailed.Dock = DockStyle.Fill;
                lblLoadingFailed.Visible = true;
            }
        }

        private void LoadJobRunningHistory(JobInfo job, bool append = false)
        {
            if (job == null)
            {
                pnlHistories.Visible = false;
            }
            else
            {
                int? lastLoadedId = null;
                if (append)
                {
                    var lastLoadedHis = (JobHistory)lstHistories.Items[lstHistories.Items.Count - 1];
                    if (lastLoadedHis != null)
                        lastLoadedId = lastLoadedHis.Id;
                }
                IEnumerable<JobHistory> histories = new SchedulerProxy().GetJobHistories(job.Name, job.Group, lastLoadedId);

                if (histories.Count() == 0)
                {
                    if (!append)
                        btnMoreHis.Enabled = false;
                    else
                        pnlHistories.Visible = false;
                }
                else
                {
                    if (!append)
                        lstHistories.Items.Clear();

                    foreach (JobHistory his in histories)
                        lstHistories.Items.Add(his);
                    
                    pnlHistories.Visible = true;
                    btnMoreHis.Enabled = true;
                }
            }
        }

        private void ListJobsInGroup()
        {
            lstJobs.Items.Clear();
            string group = lstGroups.SelectedItem as string;
            var jobsInGroup = jobs.Where(j => j.Group == group);
            foreach (JobInfo job in jobsInGroup)
            {
                lstJobs.Items.Add(job);
            }
        }

        private void RefreshList()
        {
            string selectedGroup = lstGroups.SelectedItem as string;
            LoadTasks();

            if (selectedGroup == null) return;

            int groupIndex = lstGroups.Items.IndexOf(selectedGroup);
            if (groupIndex >= 0)
                lstGroups.SelectedIndex = groupIndex;
            else
                lstJobs.Items.Clear();
            RefreshDeleteStatus();
        }

        private void NewTask()
        {
            if (new JobInfoForm().ShowDialog(this) == DialogResult.OK)
            {
                RefreshList();
            }
        }

        private void DeleteJob()
        {
            if (lstJobs.SelectedItem == null) return;
            JobInfo job = (JobInfo)lstJobs.SelectedItem;

            if (MessageBox.Show(String.Format("Do you wish to delete \"{0}\" in group \"{1}\"?", job.Name, job.Group), "", MessageBoxButtons.YesNo) != DialogResult.Yes)
                return;

            new SchedulerProxy().DeleteJob(job.Name, job.Group);
            RefreshList();
        }

        private void lstJobs_DoubleClick(object sender, EventArgs e)
        {
            if (lstJobs.SelectedItem == null) return;
            JobInfo job = (JobInfo)lstJobs.SelectedItem;
            JobInfoForm form = new JobInfoForm(job);
            if (form.ShowDialog(this) == DialogResult.OK)
                RefreshList();
        }

        private void RefreshDeleteStatus()
        {
            deleteTaskToolStripMenuItem.Enabled = deleteToolStripButton.Enabled = lstJobs.SelectedItem != null;
        }
        
        private string GetScheduleDescription(JobInfo jobInfo)
        {
            string scheduleDescription = "";
            if (jobInfo is SimpleJobInfo)
            {
                SimpleJobInfo simpJob = (SimpleJobInfo)jobInfo;
                if (simpJob.RepeatCount == 0)
                    scheduleDescription = "Run once at {START_TIME}.";
                else if (simpJob.RepeatCount < 0)
                {
                    scheduleDescription = "Run every {INTERVAL} starting from {START_TIME}";
                    if (simpJob.EndTimeUtc.HasValue)
                        scheduleDescription += ", and ending at {END_TIME}.";
                    else
                        scheduleDescription += ".";
                }
                else
                {
                    scheduleDescription = "Run every {INTERVAL} for overall {OVERALL_COUNT} times starting from {START_TIME}";
                    if (simpJob.EndTimeUtc.HasValue)
                        scheduleDescription += ", and ending at {END_TIME}.";
                    else
                        scheduleDescription += ".";
                }

                scheduleDescription = scheduleDescription.Replace("{START_TIME}", simpJob.StartTimeUtc.Value.ToLocalTime().ToString("H':'mm' on 'M'/'d'/'yy"));
                if (simpJob.EndTimeUtc.HasValue)
                    scheduleDescription = scheduleDescription.Replace("{END_TIME}", simpJob.EndTimeUtc.Value.ToLocalTime().ToString("H':'mm' on 'M'/'d'/'yy"));
                scheduleDescription = scheduleDescription.Replace("{INTERVAL}", RepeatInterval.FromTimeSpan(simpJob.Interval).ToString());
                if (simpJob.RepeatCount > 0)
                    scheduleDescription = scheduleDescription.Replace("{OVERALL_COUNT}", (simpJob.RepeatCount + 1).ToString());
            }
            return scheduleDescription;
        }

        private void btnMoreHis_Click(object sender, EventArgs e)
        {
            JobInfo job = (JobInfo)lstJobs.SelectedItem;
            if (job != null)
                LoadJobRunningHistory(job, true);
        }

        private void lstHistories_DoubleClick(object sender, EventArgs e)
        {
            JobHistory his = (JobHistory)lstHistories.SelectedItem;
            if (his == null) return;
            string log = new SchedulerProxy().GetHistoryLog(his.Id.Value);
            if (!String.IsNullOrEmpty(log))
                new HistoryLogForm(log).ShowDialog(this);
        }
    }
}
